#include "ntdtime.h"

#ifdef WIN32

#include <windows.h>
#include <time.h>
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
#define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
#else
#define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
#endif

struct timezone 
{
	int  tz_minuteswest; /* minutes W of Greenwich */
	int  tz_dsttime;     /* type of dst correction */
};

int gettimeofday(struct timeval *tv, struct timezone *tz)
{
	FILETIME ft;
	unsigned __int64 tmpres = 0;
	static int tzflag;

	if (NULL != tv)
	{
		GetSystemTimeAsFileTime(&ft);

		tmpres |= ft.dwHighDateTime;
		tmpres <<= 32;
		tmpres |= ft.dwLowDateTime;

		/*converting file time to unix epoch*/
		tmpres -= DELTA_EPOCH_IN_MICROSECS; 
		tmpres /= 10;  /*convert into microseconds*/
		tv->tv_sec = (long)(tmpres / 1000000UL);
		tv->tv_usec = (long)(tmpres % 1000000UL);
	}

	if (NULL != tz)
	{
		if (!tzflag)
		{
			_tzset();
			tzflag++;
		}
		tz->tz_minuteswest = _timezone / 60;
		tz->tz_dsttime = _daylight;
	}

	return 0;
}
#endif
//TODO: use CLOCK_MONOTONIC if available, please refer to utp, should compiled with -lrt

NtdTime::NtdTime()
{
#ifndef WIN32
	m_starttick = {0,0};
#else
	m_startPerformanceCounter = 0;
	m_counterPerMicrosecond = 0;
#endif
}

void NtdTime::Init()
{
#ifndef WIN32	
	gettimeofday(&m_starttick, NULL);
#else
	uint64 frequency;

	HANDLE hCurThread = ::GetCurrentThread();
	DWORD_PTR dwOldMask = ::SetThreadAffinityMask(hCurThread, 1);
	QueryPerformanceCounter((LARGE_INTEGER*)&m_startPerformanceCounter);
	QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
	SetThreadAffinityMask(hCurThread, dwOldMask);

	m_counterPerMicrosecond = (double)frequency / 1000000.0f;
#endif

}

uint32 NtdTime::GetCurrentTime_ms()
{
	return static_cast<uint32>(GetCurrentTime_us()/1000);
}

uint64 NtdTime::GetCurrentTime_us()
{
#ifndef WIN32
	timeval t;
	::gettimeofday(&t, NULL);
	return uint64(t.tv_sec - m_starttick.tv_sec) * 1000000 + (t.tv_usec);
#else
	uint64 counter;
	QueryPerformanceCounter((LARGE_INTEGER*) &counter);
	uint64 ret = (uint64)(((uint64)counter - (uint64)m_startPerformanceCounter) / m_counterPerMicrosecond);
    return ret;
#endif
}

//#include <sys/time.h>
//#include <stdint.h>
//#include <stdbool.h>
//#include <stddef.h>
//#include <assert.h>
//
///* Helpful conversion constants. */
//static const unsigned usec_per_sec = 1000000;
//static const unsigned usec_per_msec = 1000;
//
///* These functions are written to match the win32
//signatures and behavior as closely as possible.
//*/
//bool QueryPerformanceFrequency(int64_t *frequency)
//{
//	/* Sanity check. */
//	assert(frequency != NULL);
//
//	/* gettimeofday reports to microsecond accuracy. */
//	*frequency = usec_per_sec;
//
//	return true;
//}
//
//bool QueryPerformanceCounter(int64_t *performance_count)
//{
//	struct timeval time;
//
//	/* Sanity check. */
//	assert(performance_count != NULL);
//
//	/* Grab the current time. */
//	gettimeofday(&time, NULL);
//	*performance_count = time.tv_usec + /* Microseconds. */
//		time.tv_sec * usec_per_sec; /* Seconds. */
//
//	return true;
//}

//#include <sys/timeb.h>
//
//struct timezone 
//{
//	int  tz_minuteswest; /* minutes W of Greenwich */
//	int  tz_dsttime;     /* type of dst correction */
//};
//
//int gettimeofday(struct timeval *tv, struct timezone *tz) 
//{  
//#ifdef _WIN32_WCE
//	struct timeb tb;
//	ftime (&tb);
//#elif defined(__MINGW32__)
//	//struct __timeb64 tb;
//	//_ftime64 (&tb);
//	struct _timeb tb;
//	_ftime (&tb);
//#else
//	struct __timeb64 tb;
//	_ftime64_s (&tb);
//#endif
//
//	tv->tv_sec = (long)tb.time; // Fix: tv_sec wraps year 2038 (tv.time is ok though)
//	tv->tv_usec = tb.millitm * 1000L;
//	if( tz ){
//		tz->tz_minuteswest = tb.timezone;       /* minutes west of Greenwich  */
//		tz->tz_dsttime = tb.dstflag;    /* type of dst correction  */
//	}
//	return 0;
//}

